package com.xinchao.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.xinchao.cache.RedisCacheDao;
import com.xinchao.constant.AdvertisementConstant;
import com.xinchao.constant.CacheConstant;
import com.xinchao.dao.AdvertisementMapper;
import com.xinchao.exception.ServiceException;
import com.xinchao.model.dto.AdvertisementApiDTO;
import com.xinchao.model.dto.AdvertisementApiListDTO;
import com.xinchao.model.dto.AgeSexDTO;
import com.xinchao.service.AdvertisementService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author dxy
 * @date 2018/9/18 18:35
 */
@Service(value = "advertisementService")
public class AdvertisementServiceImpl implements AdvertisementService {
	@Autowired
	private AdvertisementMapper advertisementMapper;
	@Autowired
	private RedisCacheDao redisCacheDao;

	/**
	 * 获取品宣广告
	 * @return AdvertisementApiDTO
	 */
	@Override
	public AdvertisementApiDTO getOneDeclareGoodsAdvertisement() {
		//查询所有的品宣广告
		List<AdvertisementApiDTO> advertisementApiList = advertisementMapper.listDeclareGoodsAdvertisement();
		if (CollectionUtils.isEmpty(advertisementApiList)) {
				return null;
		}
		//如果有多个，随机选择一个
		if (advertisementApiList.size() > 1) {
			int randomIndex = RandomUtils.nextInt(0, advertisementApiList.size());
			return advertisementApiList.get(randomIndex);
		} else {
			//如果只有一个，放回一个
			return advertisementApiList.get(0);
		}
	}

	/**
	 * 获取广告列表（不包含品宣广告）
	 * @return List<AdvertisementApiDTO>
	 */
	@Override
	public List<AdvertisementApiListDTO> listAdvertisement() {
		return advertisementMapper.listAdvertisement(AdvertisementConstant.DECLARE_GOODS_ADVERTISEMENT_NO);
	}

	/**
	 * 通过年龄获取人脸识别推荐广告
	 * @param ageSexJsonArray JSONArray
	 * @return AdvertisementApiDTO
	 */
	@Override
	public AdvertisementApiDTO getFaceRecognitionAdvertisementByAgeAndSex(String deviceNumber, JSONArray ageSexJsonArray) throws ServiceException {
		if (ageSexJsonArray == null || ageSexJsonArray.size() == 0) {
			throw new ServiceException("输入参数不能为空");
		}
		//男性年龄列表
		List<Integer> maleAgeList = new ArrayList<>();
		//女性年龄列表
		List<Integer> femaleAgeList = new ArrayList<>();
		//部分性别，所有年龄
		List<Integer> allAgeList = new ArrayList<>();
		//男性数量
		int maleCount = 0;
		//女性数量
		int femaleCount = 0;
		for (int i = 0; i < ageSexJsonArray.size(); i++) {
			String ageSexStr = ageSexJsonArray.getString(i);
			if (StringUtils.isBlank(ageSexStr)) {
				continue;
			}
			AgeSexDTO ageSexDTO = JSON.parseObject(ageSexStr, AgeSexDTO.class);
			if (ageSexDTO == null) {
				continue;
			}
			//性别
			Integer sex = ageSexDTO.getSex();
			//年龄
			Integer age = ageSexDTO.getAge();
			//如果性别或者年龄为空，忽略本条数据
			if (sex == null || age == null) {
				continue;
			}
			//男性
			if (AdvertisementConstant.SEX_MALE == sex) {
				maleCount++;
				maleAgeList.add(age);
				allAgeList.add(age);
			}
			//女性
			if (AdvertisementConstant.SEX_FEMALE == sex) {
				femaleCount++;
				femaleAgeList.add(age);
				allAgeList.add(age);
			}
		}
		//男性>女性；开始判断男性年龄；比如：19-25岁阶段男性最多，最终推荐合适19-25岁男性广告
		if (maleCount > femaleCount) {
			//如果计算出的年为空，默认查询26岁~35岁的广告
			String maleAage = AdvertisementConstant.TWENTYSIX_AND_THIRTYFIVE_CH;
			//获取人数最多的年龄太
			String maleAgeRange = calculateAgeRange(maleAgeList);
			return getAdvertisementApiDTO(deviceNumber, maleAage, AdvertisementConstant.SEX_MALE, maleAgeRange);
		}
		//女性>男性；开始判断女性年龄；比如：19-25岁阶段女性最多，最终推荐适合19-25对女性的广告
		if (maleCount < femaleCount) {
			//获取人数最多的年龄太
			//年龄范围,默认是26岁~35岁
			String femeleAge = AdvertisementConstant.TWENTYSIX_AND_THIRTYFIVE_CH;
			//女性年龄范围
			String femaleAgeRange = calculateAgeRange(femaleAgeList);
			return getAdvertisementApiDTO(deviceNumber, femeleAge, AdvertisementConstant.SEX_FEMALE, femaleAgeRange);
		}
		//男性=女性
		if (maleCount == femaleCount) {
			//年龄,默认是26岁~35岁
			String age = AdvertisementConstant.TWENTYSIX_AND_THIRTYFIVE_CH;
			//获取年龄范围
			String ageRange = calculateAgeRange(allAgeList);
			//男性=女性；推荐不限广告；开始判断年龄，比如：25-35岁阶段人数最多，最终推荐适合25-35岁的不限的广告
			//男性=女性，年龄阶段相等；推荐不限广告，假如年龄阶段19-25和25-35岁阶段人数相等,随机推荐一个年龄阶段的，假如19-25岁的；最终推荐适合26-35岁
			return getAdvertisementApiDTO(deviceNumber, age, AdvertisementConstant.SEX_NO, ageRange);
		}
		return null;
	}

	/**
	 * 获取AdvertisementApiDTO
	 * @param age 年龄
	 * @param sex 性别
	 * @param ageRange 年龄范围
	 * @return AdvertisementApiDTO
	 */
	private AdvertisementApiDTO getAdvertisementApiDTO(String deviceNumber, String age, Integer sex, String ageRange) {
		if (age == null || sex == null || StringUtils.isBlank(ageRange)) {
			return null;
		}
		if (StringUtils.isNotBlank(ageRange)) {
			String[] ageArray = ageRange.split(",");
			if (ageArray.length > 1) {
				int randomInt = RandomUtils.nextInt(0, ageArray.length);
				age = ageArray[randomInt];
			} else {
				age = ageArray[0];
			}
		}
		//缓存名
		String cacheName = "";
		//男性
		if (AdvertisementConstant.SEX_MALE == sex) {
			cacheName = CacheConstant.CACHE_NAME_SEX_MALE;
		}
		//女性
		if (AdvertisementConstant.SEX_FEMALE == sex) {
			cacheName = CacheConstant.CACHE_NAME_SEX_FEMALE;
		}
		//不限性别
		if (AdvertisementConstant.SEX_NO == sex) {
			cacheName = CacheConstant.CACHE_NAME_SEX_NO;
		}
		//获取key
		String key = AdvertisementConstant.AGE_RANGE_MAP.get(age);
		//从缓存中获取
		Object obj = redisCacheDao.getCache(cacheName, key);
		List<AdvertisementApiDTO> advertisementList = null;
		if (obj == null) {
			//广告列表
			advertisementList = advertisementMapper.listAdvertisementByAgeAndSex(age, sex, AdvertisementConstant.DECLARE_GOODS_ADVERTISEMENT_NO);
			if (CollectionUtils.isEmpty(advertisementList)) {
				return null;
			}
			//放入缓存中
			redisCacheDao.putCache(cacheName, key, advertisementList);
		} else {
			advertisementList = (List<AdvertisementApiDTO>)obj;
		}
		//如果有多个，随机选择一个
		if (advertisementList.size() > 1) {
			//此次请求的广告不能与上一次请求的广告重复
			Object cache = redisCacheDao.getCache(AdvertisementConstant.DEVIICE_PREVIOUS_ADVERTISEMENT, deviceNumber);
			if (cache != null) {
				AdvertisementApiDTO  apiDTO =  (AdvertisementApiDTO)cache;
				//移除上一次已经播放的广告
				advertisementList.removeIf(dto -> dto.getAdvertisementCode().equals(apiDTO.getAdvertisementCode()));
			}
			int randomIndex = RandomUtils.nextInt(0, advertisementList.size());
			AdvertisementApiDTO preAdvertisement = advertisementList.get(randomIndex);
			preAdvertisement.setSex(sex);
			preAdvertisement.setAge(age);
			redisCacheDao.putCache(AdvertisementConstant.DEVIICE_PREVIOUS_ADVERTISEMENT, deviceNumber, preAdvertisement);
			return preAdvertisement;
		} else {
			//如果只有一个，放回一个
			AdvertisementApiDTO advertisemenAapi = advertisementList.get(0);
			advertisemenAapi.setSex(sex);
			advertisemenAapi.setAge(age);
			return advertisemenAapi;
		}
	}

	/**
	 * 计算年龄范围（返回多个年龄段，一逗号分隔）
	 * @param ageList 年龄列表
	 */
	private String calculateAgeRange(List<Integer> ageList) {
		//如果传入列表为空，返回""
		if (CollectionUtils.isEmpty(ageList)) {
			return "";
		}
		//19岁及以下人数
		int underNineteenCount = 0;
		//20岁~25岁
		int twentyAndTwentyFiveCount = 0;
		//26岁~35岁
		int twentySixAndThirtyFiveCount = 0;
		//36岁~45岁
		int thirtySixAndFourtyFiveCount = 0;
		//46岁~55岁
		int fourtySixeAndFiftyFiveCount = 0;
		//56岁及以上
		int aboveFiftyFiveCount = 0;
		for (Integer age : ageList) {
			//19岁及以下
			if (age <= 19) {
				underNineteenCount++;
			} else if (age >= 20 && age <= 25) {
				//20岁~25岁
				twentyAndTwentyFiveCount++;
			} else if (age >= 26 && age <= 35) {
				//26岁~35岁
				twentySixAndThirtyFiveCount++;
			} else if (age >= 36 && age <= 45) {
				//36岁~45岁
				thirtySixAndFourtyFiveCount++;
			} else if (age >= 46 && age <= 55) {
				//46岁~55岁
				fourtySixeAndFiftyFiveCount++;
			} else {
				//56岁及以上
				aboveFiftyFiveCount++;
			}
		}
		//年段数量统计
		Map<String, Integer> ageCountMap = new HashMap<>();
		ageCountMap.put(AdvertisementConstant.UNDER_NINETEEN_CH, underNineteenCount);
		ageCountMap.put(AdvertisementConstant.TWENTY_AND_TWENTYFIVE_CH, twentyAndTwentyFiveCount);
		ageCountMap.put(AdvertisementConstant.TWENTYSIX_AND_THIRTYFIVE_CH, twentySixAndThirtyFiveCount);
		ageCountMap.put(AdvertisementConstant.THIRTYSIX_AND_FOURTYFIVE_CH, thirtySixAndFourtyFiveCount);
		ageCountMap.put(AdvertisementConstant.FOURTYSIXE_AND_FIFTYFIVE_CH, fourtySixeAndFiftyFiveCount);
		ageCountMap.put(AdvertisementConstant.ABOVE_FIFTYFIVE_CH, aboveFiftyFiveCount);
		//选出人数最多的年段，如果有相等的情况，随机选择
		//value值
		Collection<Integer> values = ageCountMap.values();
		Object[] objects = values.toArray();
		Arrays.sort(objects);
		//最多人数值
		Object max = objects[objects.length - 1];
		//根据value值查找key
		Set<Map.Entry<String, Integer>> entrySet = ageCountMap.entrySet();
		Iterator<Map.Entry<String, Integer>> iterator = entrySet.iterator();
		//拼接相等的年龄段，已逗号分隔
		StringBuilder sb = new StringBuilder();
		while (iterator.hasNext()) {
			Map.Entry<String, Integer> entry = iterator.next();
			Integer value = entry.getValue();
			if (max.equals(value)) {
				if (sb.length() > 0) {
					sb.append(",");
				}
				sb.append(entry.getKey());
			}
		}
		return sb.toString();
	}

}
